package ar.com.larreta.colegio.procesos.pasos;

import java.util.Collection;

import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;

import ar.com.larreta.colegio.entidades.Obligacion;
import ar.com.larreta.colegio.entidades.Pago;
import ar.com.larreta.colegio.entidades.UnidadDePago;
import ar.com.larreta.colegio.intercambio.client.ListaDeDeudasPorAlumno;
import ar.com.larreta.comunes.Transformador;
import ar.com.larreta.procesos.pasos.GenerarCriteria;

public class GenerarCriteriaDeudasPorAlumno extends GenerarCriteria {

	public static final String ALIAS_OBLIGACION_MAS_RECIENTE = "OMR";
	public static final String ALIAS_UNIDAD_PAGO = "AUP";
	public static final String ALIAS_OBLIGACION = "AO";
	public static final String FECHA_CREACION = "fechaCreacion";
	public static final String FECHA_ELIMINACION = "fechaEliminacion";
	public static final String ITEM = "item";
	public static final String OBLIGACION = "obligacion";
	public static final String PUNTO_ITEM = PUNTO + ITEM;
	public static final String PUNTO_OBLIGACION = PUNTO + OBLIGACION;
	public static final String PLAN_DE_PAGO = "planDePago";
	
	@Override
	protected void accion() {
		super.accion();
		
		Criteria criteriaLista = (Criteria) salidas.get(CRITERIA_LISTA);
		Criteria criteriaContar = (Criteria) salidas.get(CRITERIA_CONTAR);
		
		ListaDeDeudasPorAlumno pedido = (ListaDeDeudasPorAlumno) getProceso().getPedido();
		
		Transformador transformador = new Transformador();
		Collection planes = null;
		try {
			planes = (Collection) transformador.getObjetoNuevo(pedido.getAlumno().getPlanesDePagos());
		} catch (Exception e) {
			logger.error(e);
		}
		
		criteriaLista = subqueryPagosRealizados(criteriaLista);
		criteriaContar = subqueryPagosRealizados(criteriaContar);
		
		criteriaLista = subqueryObligacionMasReciente(criteriaLista);
		criteriaContar = subqueryObligacionMasReciente(criteriaContar);
		
		criteriaLista = filtrarPorPlanesDePago(planes, criteriaLista);		
		criteriaContar = filtrarPorPlanesDePago(planes, criteriaContar);
		
		//FIXME: Falta criterio para obtencion de obligaciones que fueron pagadas parcialmente
		
		salidas.put(CRITERIA_LISTA, criteriaLista);
		salidas.put(CRITERIA_CONTAR, criteriaContar);
	}

	public Criteria subqueryPagosRealizados(Criteria criteria) {
		DetachedCriteria sub = DetachedCriteria.forClass(UnidadDePago.class, ALIAS_UNIDAD_PAGO);
		sub = sub.setFetchMode(OBLIGACION, FetchMode.JOIN);
		sub.setProjection(Projections.property(OBLIGACION + PUNTO_ID));
		sub.add(Restrictions.eqProperty(OBLIGACION + PUNTO_ID, ALIAS_ENTIDAD_PRINCIPAL + PUNTO_ID));
	
		criteria.add(Subqueries.notExists(sub));
				
		return criteria;
	}

	public Criteria subqueryObligacionMasReciente(Criteria criteria) {
		DetachedCriteria sub = DetachedCriteria.forClass(Obligacion.class, ALIAS_OBLIGACION_MAS_RECIENTE);
		sub.setProjection(Projections.projectionList().add( Projections.max(FECHA_CREACION)));
		sub.add(Restrictions.isNull(FECHA_ELIMINACION));
		sub.add(Restrictions.eqProperty(ALIAS_OBLIGACION_MAS_RECIENTE + PUNTO_ITEM, ALIAS_ENTIDAD_PRINCIPAL + PUNTO_ITEM));
		
		criteria.add(Property.forName(FECHA_CREACION).eq(sub));

		return criteria;
	}

	public Criteria filtrarPorPlanesDePago(Collection planes, Criteria criteria) {
		criteria = criteria.createCriteria(ITEM);
		criteria.add(Restrictions.in(PLAN_DE_PAGO, planes));
		return criteria;
	}

}
